
import bpy



def f_get容器父节点(当前所在树):
	当前所在树_上层树 = 当前所在树.m_父节点树
	return 当前所在树_上层树.nodes[ 当前所在树.m_RootNodeName ]


def f_get输出组节点连接插座(input插座, node):
	连接到的插座 = []
	容器节点 = f_get容器父节点(node.id_data)
	#print('输出组节点连接插座 ==== ', 容器节点, 容器节点.outputs)
	for 外部节点输出插座 in 容器节点.outputs :
		if 外部节点输出插座.identifier == input插座.identifier :
			子节点输入插座组 = f_get子节点输入插座_穿过子树([外部节点输出插座])
			#print('*** 子节点输入插座组 ==== ', 子节点输入插座组)
			for i in 子节点输入插座组:
				连接到的插座.append(i)
			break
	#print('取得输出节点连接到的输入插座', 连接到的插座)
	return 连接到的插座

def f_get子节点输入插座_穿过子树(输出插座, 接入节点输出插座=None):
	连接到的节点 = []
	
	for outs in 输出插座:
		if outs.is_linked:
			for link in outs.links:
				链向节点的输入插座 = link.to_socket
				链向的节点 = 链向节点的输入插座.node
				#print(' A 链向的节点   =====  ', 链向的节点, 链向的节点.type, 链向的节点.bl_static_type, 链向的节点.bl_idname)
				if 链向的节点.type == 'REROUTE' or 链向的节点.bl_idname == 'C_SceneNode_流程合并' :
					连接到的节点.extend( f_get子节点输入插座_穿过子树(链向的节点.outputs) )
				elif 链向的节点.bl_static_type == 'GROUP' :
					#print('链向的节点 = ', 链向的节点)
					#当前连接的插座找到组内部输入面板输出插座
					for 内部输入节点子节点输入插座 in 链向的节点.node_tree.nodes['Group Input'].outputs :
						if 内部输入节点子节点输入插座.identifier == 链向节点的输入插座.identifier :
							#内部输入节点输出插座 = 链向的节点.node_tree.nodes['Group Input'].outputs
							内部输入节点输出插座 = f_get子节点输入插座_穿过子树([内部输入节点子节点输入插座])
							#print('内部输入节点输出插座 = ', 内部输入节点输出插座)
							连接到的节点.extend( 内部输入节点输出插座 )
					#内部输入节点输出插座 = 链向的节点.node_tree.nodes['Group Input'].outputs[链向节点的输入插座.name]
					#遇到组节点更新整个组
					链向的节点.f_pushUpdate()

				elif 链向的节点.bl_static_type == 'GROUP_OUTPUT' :
					#print('开始更新组节点输出节点插座')
					input插座组 = f_get输出组节点连接插座(链向节点的输入插座, 链向的节点)
					连接到的节点.extend(input插座组)
				else:
					连接到的节点.append(链向节点的输入插座)
	#print('连接到的节点 = ', 连接到的节点)	
	return 连接到的节点



def f_递归到子节点Update(输出插座, 是否传递=True, 接入节点输出插座=None):
	连接到的节点 = []

	for outs in 输出插座:
		#print("outs A = ", outs.name, outs.node.name)
		if outs.is_linked and (outs.bl_idname == 'NodeSocketColor' or outs.f_is未更新()): # 
			#print("outs B = ", outs.name, outs.node.name)
			for link in outs.links:
				链向节点的输入插座 = link.to_socket
				链向的节点 = 链向节点的输入插座.node

				if 接入节点输出插座 == None :
					接入节点输出插座 = outs

				#print('B 是否传递   =====  ', 是否传递, 链向的节点, 链向的节点.type, 链向的节点.bl_static_type, 链向的节点.bl_idname)
				#print('B 是否传递   =====  ', 链向的节点.bl_idname, 接入节点输出插座)
				if 链向的节点.type == 'REROUTE' or 链向的节点.bl_idname == 'C_SceneNode_流程合并' :
					f_递归到子节点Update(链向的节点.outputs, 是否传递, 接入节点输出插座=接入节点输出插座)
				elif 链向的节点.bl_static_type == 'GROUP' :
					#容器节点对外接口更新
					#print('子节点输入插座 ========== ', 链向的节点, 链向节点的输入插座)
					for 内部输入节点子节点输入插座 in 链向的节点.node_tree.nodes['Group Input'].outputs :
						if 内部输入节点子节点输入插座.identifier == 链向节点的输入插座.identifier :
							子节点输入插座组 = f_get子节点输入插座_穿过子树([内部输入节点子节点输入插座], 接入节点输出插座=接入节点输出插座)
							#print('子节点输入插座 ========== ', 子节点输入插座组, 内部输入节点子节点输入插座, 内部输入节点子节点输入插座.links, 内部输入节点子节点输入插座.identifier)
							for i in 子节点输入插座组:
								#print('是否传递   =====  ', i.node, i.node.type, i.node.bl_static_type)
								if i.node.bl_static_type == 'GROUP_OUTPUT' :
									输出组节点连接插座 = f_get输出组节点连接插座(i, i.node)
									for i in 输出组节点连接插座:
										i.node.f_input插座Update(i, 上层Output=接入节点输出插座)
										
								else:
									i.node.f_input插座Update(i, 上层Output=接入节点输出插座)
							break
					#内部输入节点输出插座 = 链向的节点.node_tree.nodes['Group Input'].outputs[链向节点的输入插座.name]
					#内部输入节点子节点输入插座 = f_get子节点输入插座([内部输入节点输出插座])
					#遇到组节点更新整个组
					链向的节点.f_pushUpdate()


				elif 链向的节点.bl_static_type == 'GROUP_OUTPUT' :
					#print('GROUP_OUTPUT   =====  update')
					#取得外部输出插座
					input节点组 = f_get输出组节点连接插座(链向节点的输入插座, 链向的节点)
					#print('GROUP_OUTPUT   =====  取得外部输出插座', input节点组)
					for i in input节点组:
						#print('input插座组   =====  ', i, 接入节点输出插座)
						i.node.f_input插座Update(i, 上层Output=接入节点输出插座)
				else:
					#print('链向节点的输入插座 === ', 接入节点输出插座, type(链向的节点), 链向的节点, 链向节点的输入插座)
					链向的节点.f_input插座Update(链向节点的输入插座, 上层Output=接入节点输出插座)
					#return 链向的节点












	
def f_get子节点(输出插座s):
	连接到的节点 = {}

	for outs in 输出插座s:
		#print('f_get子节点 --A-- ', outs, outs.node, outs.bl_idname)
		if outs.is_linked and (outs.bl_idname == 'NodeSocketColor' or outs.f_is未更新()):
			#print('f_get子节点 --B-- ', outs, outs.node, outs.bl_idname)
			for link in outs.links:
				链向节点的输入插座 = link.to_socket
				链向的节点 = 链向节点的输入插座.node
				
				if 链向的节点.type == 'REROUTE' or 链向的节点.bl_idname == 'C_SceneNode_流程合并':
					newNode = f_get子节点(链向的节点.outputs)
					连接到的节点 = {**newNode, **连接到的节点 }
					
				else:
					if 链向的节点.type == 'GROUP_OUTPUT' :
						容器节点 = f_get容器父节点(链向的节点.id_data)
						for 外部节点输出插座 in 容器节点.outputs :
							if 外部节点输出插座.identifier == 链向节点的输入插座.identifier :
								newNode = f_get子节点([外部节点输出插座])
								连接到的节点 = {**newNode, **连接到的节点 }
								break
					else:
						连接到的节点[链向的节点.name] = 链向的节点
	#print('连接到的节点 = ', 连接到的节点)	
	return 连接到的节点







def f_get子节点and输入插座(输出插座s):
	连接到的节点 = []
	
	for outs in 输出插座s:
		if outs.is_linked:
			for link in outs.links:
				链向节点的输入插座 = link.to_socket
				链向的节点 = 链向节点的输入插座.node
				
				if 链向的节点.bl_idname == 'C_SceneNode_流程合并':
					连接到的节点.extend( f_get子节点and输入插座(链向的节点.outputs) )
					
				elif 链向的节点.type == 'REROUTE' :
					newNode = f_get子节点(链向的节点.outputs)
					newNode = list(newNode.values())
					
					连接到的节点.extend( newNode )

				else:
					连接到的节点.append((链向的节点, 链向节点的输入插座))

	return 连接到的节点














def f_get上一层Output插座(输入插座):
	if 输入插座.is_linked :
		当前连接 = 输入插座.links[0]
		
		if 当前连接.from_node.bl_idname == 'C_SceneNode_流程合并' :
			#socknum = len(当前连接.from_node.inputs)
			#for i in range(1, socknum):
			#	in_sock = 当前连接.from_node.inputs[i]
			#	if in_sock.id_linked:
			#		s = f_get上一层Output插座([in_sock])
			#		pass
			return None
		elif 当前连接.from_node.type == 'REROUTE' :
			for 连接到的插座 in 当前连接.from_node.inputs:
				return f_get上一层Output插座(连接到的插座)
		elif 当前连接.from_node.type == 'GROUP_INPUT' :
			输入组输出插座 = 当前连接.from_socket
			外部父节点 = f_get容器父节点(当前连接.from_node.id_data)
			for 外部节点输入插座 in 外部父节点.inputs :
				if 外部节点输入插座.identifier == 输入组输出插座.identifier :
					return f_get上一层Output插座(外部节点输入插座)
		elif 当前连接.from_node.type == 'GROUP' :
			容器输出插座 = 当前连接.from_socket
			#print('容器输出插座  .from_node = ', 容器输出插座)
			组节点内输出节点组 = 当前连接.from_node.node_tree.nodes['Group Output']
			for s in 组节点内输出节点组.inputs:
				if s.identifier == 容器输出插座.identifier :
					#s = f_get上一层Output插座(s)
					#print('当前连接.from_node = ', s, s.identifier)
					return f_get上一层Output插座(s)
			
		return 当前连接.from_socket

	else:
		return None


def f_from上一层节点(输入插座):
	nodeGroup = []

	if type(输入插座).__name__ == 'bpy_prop_collection': return []
	#print('输入插座 = ', type(输入插座).__name__, 输入插座)
#	print('输入插座 = ', type(输入插座), 输入插座.type)
	if 输入插座.is_linked :
		当前连接 = 输入插座.links[0]

		node = 当前连接.from_node
		#print(node.bl_idname)  or node.bl_idname == 'C_SceneNode_流程合并' 
		if node.type == 'REROUTE':
			for 连接到的插座 in node.inputs:
				#print('连接到的插座.Node.type = ', 连接到的插座.type)
				if type(连接到的插座).__name__ == 'bpy_prop_collection':
					continue
				上一个Node = f_from上一层节点(连接到的插座)
				if len(上一个Node) :
					nodeGroup.extend(上一个Node)
			#return nodeGroup
		#elif node.type == 'REROUTE':
		else:
			nodeGroup = [node]

	return nodeGroup
	#return None



def f_反向get节点(inputs, 结束节点name组, 节点组):
	当前层节点 = []
	for i in inputs:
		if i.is_linked:
			node = i.links[0].from_node
			#print('links = ', (node.name in 结束节点name组), node.name, 结束节点name组)
			if (node.name in 结束节点name组) == False:
				当前层节点.append(node)
	#print('当前层节点 = ', 当前层节点, 节点组)
	要递归的节点 = []
	for node in 当前层节点:
		#print('节点组 = ', node.name, node.name in 节点组.keys())
		if (node.name in 节点组.keys()) == False:
			要递归的节点.append(node)
			if node.type != 'REROUTE' :
				节点组[node.name] = node

	#print('要递归的节点 = ', 要递归的节点)
	for node in 要递归的节点:
		#print('   node.name  = ', node.name, node.name in 结束节点name组)
		if (node.name in 结束节点name组) == False:
			#print('node.inputs = ', node.inputs)
			f_反向get节点(node.inputs, 结束节点name组, 节点组)



# and node.m_Type != '引用镜像'

def f_node_是否需要更新(node):
	#print('f_node_是否需要更新 = ', node.name, node.type)  and node.type != 'FRAME'
	if node.type != 'REROUTE':
		#要更新的节点 = []
		#for n in node:
		#	print(' for n in node = ', n, n.f_is未更新(), n.f_is自动Update() )
		if node.f_is未更新() or node.f_is自动Update() :
			return True
			#	要更新的节点.append(n)
		#return 要更新的节点
	return False



def f_设置下层节点为以更新状态(node):
	
	连接到的节点 = f_get子节点(node.outputs)
	#print('-- B -- 连接到的节点 = ', 连接到的节点)
	for key in 连接到的节点:
		currentNode = 连接到的节点[key]
		#print('currentNode.type = ', currentNode.type)
		if currentNode.type == 'GROUP' or currentNode.type == 'GROUP_INPUT':
			continue
		#print('-- A -- f_设置下层节点为以更新状态 = ', currentNode.inputs)
		上一层节点 = f_from上一层节点( currentNode.inputs )
		is当前节点 = True
		for upNode in 上一层节点:
			if upNode.f_is未更新() :
				is当前节点 = False
				break

		if is当前节点 :
			currentNode.f_标记为已更新()
			f_设置下层节点为以更新状态(currentNode)











classes = (
	
)




def register():
	for c in classes:
		bpy.utils.register_class(c)
		

def unregister():
	for c in classes:
		bpy.utils.unregister_class(c)

	

